package com.wlyuan.open.scanner.domain.transport;

import com.wlyuan.open.scanner.dao.entity.OrderIndexDO;
import com.wlyuan.open.scanner.domain.attach.Attach;
import com.wlyuan.open.scanner.domain.order.OrderGoods;
import com.wlyuan.open.scanner.domain.order.OrderGoodsConvert;
import com.wlyuan.open.scanner.domain.order.mapping.*;
import com.wlyuan.open.scanner.domain.transport.mapping.CacheCostMapping;
import com.wlyuan.open.scanner.domain.transport.mapping.CloseMapping;
import com.wlyuan.open.scanner.domain.transport.mapping.ScoreMapping;
import com.wlyuan.open.scanner.domain.transport.mapping.SignReceiptMapping;
import com.wlyuan.open.scanner.utils.JsonUtils;
import com.wlyuan.open.scanner.utils.enums.order.OrderStatusEnum;
import com.wlyuan.open.scanner.utils.enums.transport.TransportStatusEnum;
import com.wlyuan.open.scanner.utils.mappings.BaseMapping;
import com.wlyuan.open.scanner.utils.mappings.MappingInvalid;
import com.wlyuan.open.utils.LongUtils;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.mapstruct.*;
import org.mapstruct.factory.Mappers;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author lijing
 * @description
 */
@Slf4j
public class TransportConvert {

    private static final Convert CONVERT = Mappers.getMapper(Convert.class);

    @Mapper(uses = MappingInvalid.class)
    public interface Convert {

        @Mappings({
                @Mapping(target = "id", source = "indexId"),
                @Mapping(target = "sourceKey", source = "indexId"),
                @Mapping(target = "createTime", source = "indexCreatetime"),
                @Mapping(target = "tenantId", source = "indexCreatorcompanyid"),

                @Mapping(target = "info.upTransportId", source = "upTransportId"),
                @Mapping(target = "info.orderId", source = "indexRootorderid"),
                @Mapping(target = "info.dispatchBy", source = "dispatchBy"),
                @Mapping(target = "info.dispatchAt", source = "dispatchAt"),
                @Mapping(target = "info.createBy", source = "indexCreator"),
                @Mapping(target = "info.updateAt", source = "indexStatustime"),
                @Mapping(target = "info.createType", source = "indexCreatetype"),
                @Mapping(target = "info.waybillType", source = "indexSrcclass"),
                @Mapping(target = "info.followWaybill", source = "indexOrdertype"),
                @Mapping(target = "info.echo", source = "indexEcho"),
                @Mapping(target = "info.orderTenantId", source = "orderTenantId"),
                @Mapping(target = "info.orderCustomerId", source = "orderCustomerId"),
                @Mapping(target = "info.orderCustomerType", source = "orderCustomerType"),
                @Mapping(target = "info.orderCustomerName", source = "orderCustomerName"),
                @Mapping(target = "info.orderCreateBy", source = "orderCreateBy"),

                @Mapping(target = "finance.financeFlag", source = "financeStatus"),
                @Mapping(target = "finance.prepayFeeFlag", source = "prepayFeeFlag"),
                @Mapping(target = "finance.arrivePayFeeFlag", source = "arrivePayFeeFlag"),
                @Mapping(target = "finance.collectionFeeFlag", source = "collectionFeeFlag"),

        })
        @BaseMapping
        @CacheCostMapping
        @InfoMapping
        @FromMapping
        @ToMapping
        @PriceMapping
        @VehicleMapping
        @RequirementMapping
        @CloseMapping
        Transport convert(OrderIndexDO source);

        @AfterMapping
        default void after(@MappingTarget Transport target, OrderIndexDO source) {
            target.setRaw(JsonUtils.withNullJson(source));
        }

        List<Transport> convert(List<OrderIndexDO> list);

        @Mappings({
                @Mapping(target = "source", source = "syncThisTag"),
        })
        TransportAttach convertAttach(Attach source);

        List<TransportAttach> convertAttach(List<Attach> source);

        @Mappings({
                @Mapping(target = "status", source = "transportStatus"),
                @Mapping(target = "split", source = "indexBesplit"),
                @Mapping(target = "splitType", source = "indexSplittype"),
                @Mapping(target = "combine", source = "indexCombined"),
                @Mapping(target = "tenantId", source = "indexCreatorcompanyid"),
                @Mapping(target = "waybillType", source = "indexSrcclass"),
        })
        @SignReceiptMapping
        @ScoreMapping
        TransportRelation convertRelation(OrderIndexDO source);


        @Mappings({
                @Mapping(target = "status", source = "transportStatus"),
                @Mapping(target = "tenantId", source = "upTenantId"),
                @Mapping(target = "carrierId", source = "carrierId"),
                @Mapping(target = "carrierName", source = "carrierName"),
                @Mapping(target = "contactName", source = "carrierContactName"),
                @Mapping(target = "contactMobile", source = "carrierPhone"),
                @Mapping(target = "driverId", source = "indexDriverid"),
                @Mapping(target = "vehicleId", source = "indexCarid"),
                @Mapping(target = "carrierType", source = "carrierType"),
                @Mapping(target = "financeStatus", source = "carrierFinanceStatus"),
                @Mapping(target = "divided", source = "indexBesplit"),
                @Mapping(target = "divideMode", source = "indexSplittype"),
                @Mapping(target = "combined", source = "indexCombined"),
                @Mapping(target = "waybillType", source = "indexSrcclass"),
        })
        @SignReceiptMapping
        @ScoreMapping
        TransportCarrier convertCarrier(OrderIndexDO source);

        @Mappings({
                @Mapping(target = "customerId", source = "indexCustomerid"),
                @Mapping(target = "customerName", source = "customerName"),
                @Mapping(target = "customerType", source = "customerType"),
                @Mapping(target = "status", source = "transportStatus"),
                @Mapping(target = "tenantId", source = "downTenantId"),
                @Mapping(target = "financeStatus", source = "customerFinanceStatus"),
                @Mapping(target = "divided", source = "indexBesplit"),
                @Mapping(target = "divideMode", source = "indexSplittype"),
                @Mapping(target = "combined", source = "indexCombined"),
                @Mapping(target = "waybillType", source = "indexSrcclass"),
        })
        @SignReceiptMapping
        @ScoreMapping
        TransportCustomer convertCustomer(OrderIndexDO source);
    }

    public static List<Transport> convert(List<OrderIndexDO> creation) {
        return CONVERT.convert(creation);
    }

    public static Transport convert(OrderIndexDO source, Long down) {
        var convert = CONVERT.convert(source);
        Optional.ofNullable(convert.getInfo().getEcho()).ifPresent(h -> {
            h.put("upKey", source.getIndexId());
            if (LongUtils.notNullLong(down)) {
                h.put("downKey", down);
            }
        });
        if (source.isQuotation()) {
            convert.setCost(null);
        }
        //无承运方 和 司机
        if (convert.getCarrier() != null && convert.getCarrier().getCarrierType() == null && !LongUtils.notNullLong(source.getIndexDriverid())) {
            convert.setCarrier(null);
        }
        //无关单
        if (convert.getClose() != null && !LongUtils.notNullLong(convert.getClose().getFlowId())) {
            convert.setClose(null);
        }
        //车辆
        if (!source.isVehicle()) {
            convert.setVehicle(null);
        }
        return convert;
    }

    public static TransportCarrier convertCarrier(OrderIndexDO source) {
        var up = CONVERT.convertCarrier(source);
        Optional.ofNullable(up).ifPresent(u -> {
            //无签收人
            if (!source.isSign()) {
                u.setSign(null);
            }
            //无回单
            if (!source.isReceipt()) {
                u.setReceipt(null);
            }
            if (Optional.ofNullable(u.getSign()).isPresent() || Optional.ofNullable(u.getReceipt()).isPresent()) {
                signReceiptGoods(source, u.getSign(), u.getReceipt());
            }
            //状态16
            if (OrderStatusEnum.ALREADY.getValue().equals(source.getIndexStatus()) && source.isSign()) {
                u.setStatus(TransportStatusEnum.WAIT_RECEIPT);
            }
            //状态16
            if (OrderStatusEnum.ALREADY.getValue().equals(source.getIndexStatus()) && source.isReceipt()) {
                u.setStatus(TransportStatusEnum.DONE);
            }
        });
        return up;
    }

    public static TransportCustomer convertCustomer(OrderIndexDO source) {
        var down = CONVERT.convertCustomer(source);
        Optional.ofNullable(down).ifPresent(d -> {
            //无签收人
            if (!source.isSign()) {
                d.setSign(null);
            }
            //无回单
            if (!source.isReceipt()) {
                d.setReceipt(null);
            }
            //无关单
            if (Optional.ofNullable(d.getSign()).isPresent() || Optional.ofNullable(d.getReceipt()).isPresent()) {
                signReceiptGoods(source, d.getSign(), d.getReceipt());
            }
            //状态16
            if (OrderStatusEnum.ALREADY.getValue().equals(source.getIndexStatus()) && source.isSign()) {
                d.setStatus(TransportStatusEnum.WAIT_RECEIPT);
            }
            //状态16
            if (OrderStatusEnum.ALREADY.getValue().equals(source.getIndexStatus()) && source.isReceipt()) {
                d.setStatus(TransportStatusEnum.DONE);
            }
        });
        return down;
    }

    private static void signReceiptGoods(OrderIndexDO source, TransportSign sign, TransportReceipt receipt) {
        var goodsList = source.getGoodsList();
        if (!CollectionUtils.isEmpty(goodsList)) {
            Optional.ofNullable(sign).ifPresent(s -> {
                if (s.getSignBy() == null) {
                    s.setSignBy(0L);
                }
                var list = goodsList.stream().map(OrderGoods::getGoodsSign).collect(Collectors.toList());
                list.stream().forEach(x -> x.setTenantId(s.getTenantId()));
                s.setGoodsSign(list);
            });

            Optional.ofNullable(receipt).ifPresent(r -> {
                if (r.getReceiptBy() == null) {
                    r.setReceiptBy(0L);
                }
                if (source.isSignToReceipt()) {
                    r.setGoodsReceipt(OrderGoodsConvert.convertReceipt(goodsList.stream().map(OrderGoods::getGoodsSign).collect(Collectors.toList())));
                } else {
                    var list = goodsList.stream().map(OrderGoods::getGoodsReceipt).collect(Collectors.toList());
                    list.stream().forEach(x -> x.setTenantId(r.getTenantId()));
                    r.setGoodsReceipt(list);
                }
            });
        }
    }

    public static List<TransportAttach> convertAttach(List<Attach> source) {
        return CONVERT.convertAttach(source);
    }
}
